﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using log4net;

namespace FileConvert
{
    /// <summary>
    /// 文件转换基类
    /// </summary>
    internal abstract class ConvertBase
    {

        static ILog _log;
        public ConvertBase()
        {
            log4net.Config.XmlConfigurator.Configure();
            _log = LogManager.GetLogger(GetType());
        }
        #region Properties
        /// <summary>
        /// 转换后存储的路径　
        /// </summary>
        protected string strTempSavePath = System.Configuration.ConfigurationManager.AppSettings["SavePath"].ToString();

        /// <summary>
        /// 原文件路径
        /// </summary>
        protected string strOldPath = System.Configuration.ConfigurationManager.AppSettings["OldPath"].ToString();


        /// <summary>
        /// 可以接受的文件格式
        /// </summary>
        protected string videoFormat
        {
            get
            {
                return System.Configuration.ConfigurationManager.AppSettings["VideoFormat"].ToString();
            }
        }
        /// <summary>
        /// 解码程序
        /// </summary>
        protected string strFfmpegPath
        {
            get
            {
                return AppDomain.CurrentDomain.BaseDirectory + (@"\Dependencies\ffmpeg.exe");
            }
        }

        protected string BigImageSize = System.Configuration.ConfigurationManager.AppSettings["BigImage"].ToString();
        protected string SmallImageSize = System.Configuration.ConfigurationManager.AppSettings["SmallImage"].ToString();
        #endregion

        #region Methods
        /// <summary>
        /// 视频转换功能方法
        /// </summary>
        /// <param name="type"></param>
        /// <param name="path"></param>
        /// <param name="IsGenerateImage"></param>
        /// <returns>返回文件的时长</returns>
        protected virtual MessageEntity ConvertFile(string stringArguments, string extName, string path, bool IsGenerateImage)
        {

            StringBuilder message = new StringBuilder();
            int iTimeLength = 0;
            int result = 0;
            try
            {
                string strFileType = path.Substring(path.LastIndexOf("."));
                //源文件路径
                strOldPath = strOldPath + path.Replace("/", "\\");
                //保存相对路径
                string strTmepPath = strOldPath.Substring(0, strOldPath.LastIndexOf(@"\"));
                if (File.Exists(strOldPath))//源文件存在
                {
                    if (!Directory.Exists(strTmepPath))//保存文件的路径不存在 就创建
                    {
                        Directory.CreateDirectory(strTmepPath);
                    }

                    if (videoFormat.IndexOf(strFileType) > -1)
                    {

                        #region //视频格式
                        strTempSavePath = strTempSavePath + path.Replace("/", "\\").Replace(strFileType, extName);

                        string strImagePath = strTempSavePath.Substring(0, strTempSavePath.LastIndexOf("\\"));
                        if (!Directory.Exists(strImagePath))
                        {
                            Directory.CreateDirectory(strImagePath);
                        }

                        if (File.Exists(strTempSavePath))
                        {
                            File.Delete(strTempSavePath);
                        }

                        //获取时长 //视频宽度和高度
                        Process p = new Process();//建立外部调用线程 
                        p.StartInfo.FileName = strFfmpegPath; //要调用外部程序的绝对路径 
                        p.StartInfo.Arguments = " -i \"" + strOldPath.Trim() + "\"";//参数(这里就是FFMPEG的参数了)
                        p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动线程(一定为FALSE,详细的请看MSDN) 
                        p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中(这个一定要注意,FFMPEG的所有输出信息,都为错误输出流,用StandardOutput是捕获不到任何消息的...这是我耗费了2个多月得出来的经验...mencoder就是用standardOutput来捕获的) 
                        p.StartInfo.CreateNoWindow = false;//不创建进程窗口 
                        p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
                        p.Start();//启动线程 
                        // p.WaitForExit();//等待完成 
                        string str = p.StandardError.ReadToEnd();//开始同步读取 
                        p.Close();//关闭进程 
                        p.Dispose();//释放资源 
                        //处理方法...
                        Regex reg = new Regex("duration:\\s*(.*?),", RegexOptions.Compiled | RegexOptions.IgnoreCase);

                        if (reg.IsMatch(str))
                        {
                            Match match = reg.Match(str);
                            iTimeLength = GetSecondsByString(match.Groups[1].Value);
                        }

                        Regex reg1 = new Regex("\\s(\\d+)[x](\\d+)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
                        string strSize = string.Empty;
                        if (reg1.IsMatch(str))
                        {
                            Match match = reg1.Match(str);
                            strSize = match.Groups[0].Value;
                            string[] strArray = strSize.Split('x');
                            if (strArray.Length == 2)
                            {
                                int iWidth = int.Parse(strArray[0]);
                                int iHeight = int.Parse(strArray[1]);
                                if (System.Convert.ToDecimal(iWidth * 1.0 / iHeight) == System.Convert.ToDecimal(16.0 / 9))
                                {
                                    BigImageSize = System.Configuration.ConfigurationManager.AppSettings["BigImage2"].ToString();
                                    SmallImageSize = System.Configuration.ConfigurationManager.AppSettings["SmallImage2"].ToString();
                                }
                            }
                        }
                        CreateProcessForFFMpeg(strFfmpegPath
                      , string.Format(stringArguments, strOldPath, strTempSavePath)
                      , true);


                        //检测是否转换成功  检测文件是否存在并且文件大小是否为0
                        if (File.Exists(strTempSavePath) && new FileInfo(strTempSavePath).Length > 0)
                        {

                            if (IsGenerateImage)
                            {
                                #region 生成图像
                                string strBigImagePath = strTempSavePath.Replace(extName, "_Big.jpg");
                                string strSmallImagePath = strTempSavePath.Replace(extName, "_Small.jpg");
                                try
                                {
                                    GeneratorImage(strBigImagePath, strSmallImagePath);
                                }
                                catch (Exception ex)
                                {

                                    _log.Info("生成图像" + ex);
                                }

                                #endregion
                            }

                            message.Append("文件转换成功！\r\n");
                            result = 1;
                        }
                        else
                        {
                            message.Append("文件\"" + strOldPath + "\"转换失败！\r\n");
                        }
                        #endregion

                    }
                    else
                    {
                        message.Append("文件格式\"" + strOldPath + "\"不支持！\r\n");
                    }
                }
                else
                {
                    message.Append("文件\"" + strOldPath + "\"不存在！\r\n");
                }
                _log.Info("file convert info :" + message.ToString());

            }
            catch (Exception ex)
            {
                message.Append("文件转换异常：" + ex.Message + "\r\n");
            }
            _log.Info("file convert info :" + message.ToString());
            return new MessageEntity { FileTime = iTimeLength, Message = message.ToString(), Result = result };
        }

        /// <summary>
        /// 调用ffmpeg.exe执行相应操作
        /// </summary>
        /// <param name="stringPath">ffmpeg.exe所在路径（如:E:\ttt\ffmpeg.exe）</param>
        /// <param name="stringArguments">给ffmpeg.exe传递的参数</param>
        /// <returns></returns>
        protected static bool CreateProcessForFFMpeg(string stringPath, string stringArguments, bool boolShowDosWindow)
        {
            try
            {
                if (!System.IO.File.Exists(stringPath))
                    return false;
                ProcessStartInfo info3 = new ProcessStartInfo(stringPath);
                if (boolShowDosWindow)
                    info3.WindowStyle = ProcessWindowStyle.Normal;
                else
                    info3.WindowStyle = ProcessWindowStyle.Hidden;
                info3.Arguments = stringArguments;
                Process proc = new Process();

                proc = Process.Start(info3);
                proc.WaitForExit();
                proc.Close();
                return true;
            }
            catch (Exception e)
            {
                _log.Info("ffmpeg转换文件时出错" + e.Message);
                throw;
            }
        }

        protected int GetSecondsByString(string str)
        {

            if (string.IsNullOrEmpty(str) || str == "N/A")
                return 0;


            int intCountSeconds = 0;
            //小时
            int intHours = 0;
            Int32.TryParse(str.Substring(0, str.IndexOf(":")), out intHours);
            if (intHours > 0)
                intCountSeconds += intHours * 3600;
            //分钟
            int intMinutes = 0;
            Int32.TryParse(str.Substring(str.IndexOf(":") + 1, 2), out intMinutes);
            if (intMinutes > 0)
                intCountSeconds += intMinutes * 60;
            //秒钟
            int intSeconds = 0;
            Int32.TryParse(str.Substring(str.LastIndexOf(":") + 1, 2), out intSeconds);
            if (intSeconds > 0)
                intCountSeconds += intSeconds;

            return intCountSeconds;
        }

        /// <summary>
        /// 从视频中生成图像
        /// </summary>
        /// <param name="strBigImagePath"></param>
        /// <param name="strSmallImagePath"></param>
        protected void GeneratorImage(string strBigImagePath, string strSmallImagePath)
        {
            if (File.Exists(strBigImagePath))
            {
                File.Delete(strBigImagePath);
            }
            if (File.Exists(strSmallImagePath))
            {
                File.Delete(strSmallImagePath);
            }
            CreateProcessForFFMpeg(strFfmpegPath, " -i \"" + strOldPath + "\" -y -f image2 -ss 2 -t 0.005 -s \"" + BigImageSize + "\" \"" + strBigImagePath + "\"", false);

            CreateProcessForFFMpeg(strFfmpegPath, " -i \"" + strOldPath + "\" -y -f image2 -ss 2 -t 0.005 -s \"" + SmallImageSize + "\" \"" + strSmallImagePath + "\"", false);

            string strTemp = System.Configuration.ConfigurationManager.AppSettings["SavePath"].ToString();
            strTempSavePath = strTempSavePath.Replace(strTemp, "").Replace("\\", "/");
            strBigImagePath = strBigImagePath.Replace(strTemp, "").Replace("\\", "/");
            strSmallImagePath = strSmallImagePath.Replace(strTemp, "").Replace("\\", "/");
        }
        #endregion

    }
}
